﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClearingRestartingAutomaton.Common;

namespace ClearingRestartingAutomaton.Base
{
    /// <summary>
    /// The AutomatonLearning class represents the core learning class for Clearing Restarting Automata.
    /// </summary>
    [Serializable]
    public class AutomatonLearning
    {
        #region Constructors

        /// <summary>
        /// Default constructor of this class.
        /// </summary>
        public AutomatonLearning()
        {

        }

        #endregion

        #region Public Properties

        /// <summary>
        /// The list of learning steps.
        /// </summary>
        public List<LearningStep> Steps
        {
            get { return this.steps; }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Returns the Automaton containing the resulting set of instructions inferred from 
        /// the list of learning steps.
        /// </summary>
        /// <param name="leftContext">The left context for the list of learning steps.</param>
        /// <param name="rightContext">The right context for the list of learning steps.</param>
        /// <param name="K">The maximal length of contexts used in the inferred instructions.</param>
        /// <returns>
        /// The instance of the Automaton class containing the resulting set of instructions inferred from 
        /// the list of learning steps.
        /// </returns>
        public Automaton GetAutomaton(string leftContext, string rightContext, int K)
        {
            if (K < 1) throw new ArgumentException("K must be positive.");
            SortedDictionary<Instruction, bool> instructionSet = new SortedDictionary<Instruction, bool>();
            foreach (LearningStep learningStep in this.steps)
            {
                Instruction instruction = new Instruction(
                    learningStep.LeftContext.LastK(K),
                    learningStep.Center,
                    learningStep.Reduction,
                    learningStep.RightContext.FirstK(K));
                instructionSet[instruction] = true;
            }
            Automaton automaton = new Automaton();
            automaton.Instructions.AddRange(instructionSet.Keys);
            return automaton;
        }

        /// <summary>
        /// Returns the Automaton containing the resulting set of instructions inferred from 
        /// the list of learning steps.
        /// The default context (^, $) is used for the list of learning steps.
        /// </summary>
        /// <param name="K">The maximal length of contexts used in the inferred instructions.</param>
        /// <returns>
        /// The instance of the Automaton class containing the resulting set of instructions inferred from 
        /// the list of learning steps.
        /// </returns>
        public Automaton GetAutomaton(int K)
        {
            return this.GetAutomaton(StringDefaultValues.LeftDelimiter, StringDefaultValues.RightDelimiter, K);
        }

        #endregion

        #region Private Data Members

        private List<LearningStep> steps = new List<LearningStep>();

        #endregion
    }
}
